﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Net;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using System.Xml.Serialization;
using InneractiveAdSDK;
using Microsoft.Phone.Net.NetworkInformation;
using AdRotator.Common;

namespace AdRotator.Silverlight
{
    public partial class AdRotatorControl : UserControl, IDisposable
    {
        private bool _loaded = false;

        private bool _slidingAdHidden = false;

        private bool _slidingAdTimerStarted = false;

        public delegate void LogHandler(string message);

        public event LogHandler Log;

        private AdCulture _currentCulture = null;

        private const string SETTINGS_FILE_NAME = "AdRotatorSettings";

        /// <summary>
        /// The displayed ad control instance
        /// </summary>
        private FrameworkElement _currentAdControl;

        /// <summary>
        /// Random generato
        /// </summary>
        private static Random _rnd = new Random();

        /// <summary>
        /// List of the ad types that have failed to load
        /// </summary>
        private static List<IAdProvider> _failedAdTypes = new List<IAdProvider>();

        /// <summary>
        /// The ad settings based on which the ad descriptor for the current UI culture can be selected
        /// </summary>
        private static AdSettings _settings;

        /// <summary>
        /// Indicates whether there has been an attemt to fetch the remote settings file
        /// </summary>
        private static bool _remoteAdSettingsFetched = false;

        /// <summary>
        /// Indicates whether a network has been detected and available, is turned off if none found
        /// </summary>
        private bool _isNetworkAvailable = true;

        #region LoggingEventCode
        protected void OnLog(string message)
        {
            if (Log != null)
            {
                Log(message);
            }
        }
        #endregion

        #region SettingsUrl

        /// <summary>
        /// Gets or sets the URL of the remote ad descriptor file
        /// </summary>
        public string SettingsUrl
        {
            get { return (string)GetValue(SettingsUrlProperty); }
            set { SetValue(SettingsUrlProperty, value); }
        }

        public static readonly DependencyProperty SettingsUrlProperty = DependencyProperty.Register("SettingsUrl", typeof(string), typeof(AdRotatorControl), new PropertyMetadata("",SettingsUrlChanged));

        private static void SettingsUrlChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = d as AdRotatorControl;
            if(sender != null)
            {
                sender.OnSettingsUrlChanged(e);
            }
        }

        private void OnSettingsUrlChanged(DependencyPropertyChangedEventArgs e)
        {
            FetchAdSettingsFile();
            Invalidate();
            
        }

#endregion

        #region DefaultAdType

        public AdType DefaultAdType
        {
            get { return (AdType)GetValue(DefaultAdTypeProperty); }
            set { SetValue(DefaultAdTypeProperty, value); }
        }

        public static readonly DependencyProperty DefaultAdTypeProperty = DependencyProperty.Register("DefaultAdType", typeof(AdType), typeof(AdRotatorControl), new PropertyMetadata(AdType.None, DefaultAdTypeChanged));

        private static void DefaultAdTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = d as AdRotatorControl;
            if(sender != null)
            {
                sender.OnDefaultAdTypeChangedChanged(e);
            }
        }

        private void OnDefaultAdTypeChangedChanged(DependencyPropertyChangedEventArgs e)
        {
            Invalidate();
        }

#endregion

        #region IsEnabled

        /// <summary>
        /// When set to false the control does not display
        /// </summary>
        public new bool IsEnabled
        {
            get { return (bool)GetValue(IsEnabledProperty); }
            set { SetValue(IsEnabledProperty, value); }
        }

        public static new readonly DependencyProperty IsEnabledProperty = DependencyProperty.Register("IsEnabled", typeof(bool), typeof(AdRotatorControl), new PropertyMetadata(true, IsEnabledChanged));

        private static new void IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = d as AdRotatorControl;
            if (sender != null)
            {
                sender.OnIsEnabledChangedChanged(e);
            }
        }

        private void OnIsEnabledChangedChanged(DependencyPropertyChangedEventArgs e)
        {
            Invalidate();
        }

        #endregion

        #region SlidingAdDirection

        /// <summary>
        /// Direction the popup will hide / appear from
        /// If not set the AdControl will remain on screen
        /// </summary>
        public SlideDirection SlidingAdDirection
        {
            get { return (SlideDirection)GetValue(SlidingAdDirectionProperty); }
            set { SetValue(SlidingAdDirectionProperty, value); }
        }

        public static readonly DependencyProperty SlidingAdDirectionProperty = DependencyProperty.Register("SlidingAdDirection", typeof(SlideDirection), typeof(AdRotatorControl), new PropertyMetadata(SlideDirection.None, SlidingAdDirectionChanged));

        private static void SlidingAdDirectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = d as AdRotatorControl;
            if (sender != null)
            {
                sender.OnSlidingAdDirectionChanged(e);
            }
        }

        private void OnSlidingAdDirectionChanged(DependencyPropertyChangedEventArgs e)
        {
            switch ((SlideDirection)e.NewValue)
            {
                case SlideDirection.Left:
                    SlideOutLRAdStoryboardAnimation.To = -485;
                    SlideInLRAdStoryboardAnimation.From = -485;
                    break;
                case SlideDirection.Right:
                    SlideOutLRAdStoryboardAnimation.To = 485;
                    SlideInLRAdStoryboardAnimation.From = 485;
                    break;
                case SlideDirection.Bottom:
                    SlideOutUDAdStoryboardAnimation.To = 485;
                    SlideInUDAdStoryboardAnimation.From = 485;
                    break;
                case SlideDirection.Top:
                    SlideOutUDAdStoryboardAnimation.To = -485;
                    SlideInUDAdStoryboardAnimation.From = -485;
                    break;
                default:
                    SlideOutLRAdStoryboardAnimation.To = 0;
                    SlideInLRAdStoryboardAnimation.From = 0;
                    SlideOutUDAdStoryboardAnimation.To = 0;
                    SlideInUDAdStoryboardAnimation.From = 0;
                    break;
            }
        }


        #endregion

        #region SlidingAdDisplaySeconds

        /// <summary>
        /// Amount of time in seconds the ad is displayed on Screen if <see cref="SlidingAdDirection"/> is set to something else than None
        /// </summary>
        public int SlidingAdDisplaySeconds
        {
            get { return (int)GetValue(SlidingAdDisplaySecondsProperty); }
            set { SetValue(SlidingAdDisplaySecondsProperty, value); }
        }

        public static readonly DependencyProperty SlidingAdDisplaySecondsProperty = DependencyProperty.Register("SlidingAdDisplaySeconds", typeof(int), typeof(AdRotatorControl), new PropertyMetadata(10, SlidingAdDisplaySecondsChanged));

        private static void SlidingAdDisplaySecondsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = d as AdRotatorControl;
            if (sender != null)
            {
                sender.OnSlidingAdDisplaySecondsChanged(e);
            }
        }

        private void OnSlidingAdDisplaySecondsChanged(DependencyPropertyChangedEventArgs e)
        {
        }

        #endregion

        #region SlidingAdHiddenSeconds

        /// <summary>
        ///  Amount of time in seconds to wait before displaying the ad again 
        ///  (if <see cref="SlidingAdDirection"/> is set to something else than None).
        ///  Basically the lower this number the more the user is "nagged" by the ad coming back now and again
        /// </summary>
        public int SlidingAdHiddenSeconds
        {
            get { return (int)GetValue(SlidingAdHiddenSecondsProperty); }
            set { SetValue(SlidingAdHiddenSecondsProperty, value); }
        }

        public static readonly DependencyProperty SlidingAdHiddenSecondsProperty = DependencyProperty.Register("SlidingAdHiddenSeconds", typeof(int), typeof(AdRotatorControl), new PropertyMetadata(20, SlidingAdHiddenSecondsChanged));

        private static void SlidingAdHiddenSecondsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = d as AdRotatorControl;
            if (sender != null)
            {
                sender.OnSlidingAdHiddenSecondsChanged(e);
            }
        }

        private void OnSlidingAdHiddenSecondsChanged(DependencyPropertyChangedEventArgs e)
        {
        }

        #endregion

        #region Pubcenter
      
        #endregion

        #region AdMobAdUnitId

        public string AdMobAdUnitId
        {
            get 
            {
                if (string.IsNullOrEmpty((string)GetValue(AdMobAdUnitIdProperty)))
                {
                    SetValue(AdMobAdUnitIdProperty,GetAppID(AdType.AdMob));
                }
                return (string)GetValue(AdMobAdUnitIdProperty);
            }
            set { SetValue(AdMobAdUnitIdProperty, value); }
        }

        public static readonly DependencyProperty AdMobAdUnitIdProperty = DependencyProperty.Register("AdMobAdUnitId", typeof(string), typeof(AdRotatorControl), new PropertyMetadata("", AdMobAdUnitIdChanged));

        private static void AdMobAdUnitIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = d as AdRotatorControl;
            if (sender != null)
            {
                sender.OnAdMobAdUnitIdChanged(e);
            }
        }

        private void OnAdMobAdUnitIdChanged(DependencyPropertyChangedEventArgs e)
        {
            RemoveAdFromFailedAds(AdType.AdMob);
            Invalidate();
        }


        #endregion

        
        #region MobFox

        public string MobFoxAppId
        {
            get 
            {
                if (string.IsNullOrEmpty((string)GetValue(MobFoxAppIdProperty)))
                {
                    SetValue(MobFoxAppIdProperty,GetAppID(AdType.MobFox));
                }
                return (string)GetValue(MobFoxAppIdProperty);
            }
            set { SetValue(MobFoxAppIdProperty, value); }
        }

        public static readonly DependencyProperty MobFoxAppIdProperty = DependencyProperty.Register("MobFoxAppId", typeof(string), typeof(AdRotatorControl), new PropertyMetadata("", MobFoxAppIdChanged));


        public bool MobFoxIsTest
        {
            get { return (bool)GetValue(MobFoxIsTestProperty); }
            set { SetValue(MobFoxIsTestProperty, value); }
        }

        public static readonly DependencyProperty MobFoxIsTestProperty = DependencyProperty.Register("MobFoxIsTest", typeof(bool), typeof(AdRotatorControl), new PropertyMetadata(false, MobFoxIsTestChanged));




        private static void MobFoxIsTestChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = d as AdRotatorControl;
            if (sender != null)
            {
                sender.OnMobFoxIsTestChanged(e);
            }
        }

        private void OnMobFoxIsTestChanged(DependencyPropertyChangedEventArgs e)
        {
            RemoveAdFromFailedAds(AdType.MobFox);
            Invalidate();
        }


        private static void MobFoxAppIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = d as AdRotatorControl;
            if (sender != null)
            {
                sender.OnMobFoxAppIdChanged(e);
            }
        }

        private void OnMobFoxAppIdChanged(DependencyPropertyChangedEventArgs e)
        {
            RemoveAdFromFailedAds(AdType.MobFox);
            Invalidate();
        }


        #endregion

        #region Inneractive

        #region InneractiveAppId

        public string InneractiveAppId
        {
            get 
            {
                if (string.IsNullOrEmpty((string)GetValue(InneractiveAppIdProperty)))
                {
                    SetValue(InneractiveAppIdProperty,GetAppID(AdType.InnerActive));
                }
                return (string)GetValue(InneractiveAppIdProperty);
            }
            set { SetValue(InneractiveAppIdProperty, value); }
        }

        public static readonly DependencyProperty InneractiveAppIdProperty = DependencyProperty.Register("InneractiveAppId", typeof(string), typeof(AdRotatorControl), new PropertyMetadata(String.Empty, InneractiveAppIdChanged));

        private static void InneractiveAppIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = d as AdRotatorControl;
            if (sender != null)
            {
                sender.OnInneractiveAppIdChanged(e);
            }
        }

        private void OnInneractiveAppIdChanged(DependencyPropertyChangedEventArgs e)
        {
            RemoveAdFromFailedAds(AdType.InnerActive);
            Invalidate();
        }


        #endregion

        #region InneractiveExternalId

        public string InneractiveExternalId
        {
            get { return (string)GetValue(InneractiveExternalIdProperty); }
            set { SetValue(InneractiveExternalIdProperty, value); }
        }

        public static readonly DependencyProperty InneractiveExternalIdProperty = DependencyProperty.Register("InneractiveExternalId", typeof(string), typeof(AdRotatorControl), new PropertyMetadata(String.Empty, InneractiveExternalIdChanged));

        private static void InneractiveExternalIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = d as AdRotatorControl;
            if (sender != null)
            {
                sender.OnInneractiveExternalIdChanged(e);
            }
        }

        private void OnInneractiveExternalIdChanged(DependencyPropertyChangedEventArgs e)
        {
            Invalidate();
        }


        #endregion

        #region InneractiveGender

        public string InneractiveGender
        {
            get { return (string)GetValue(InneractiveGenderProperty); }
            set { SetValue(InneractiveGenderProperty, value); }
        }

        public static readonly DependencyProperty InneractiveGenderProperty = DependencyProperty.Register("InneractiveGender", typeof(string), typeof(AdRotatorControl), new PropertyMetadata(String.Empty, InneractiveGenderChanged));

        private static void InneractiveGenderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = d as AdRotatorControl;
            if (sender != null)
            {
                sender.OnInneractiveGenderChanged(e);
            }
        }

        private void OnInneractiveGenderChanged(DependencyPropertyChangedEventArgs e)
        {
            Invalidate();
        }


        #endregion

        #region InneractiveAge

        public string InneractiveAge
        {
            get { return (string)GetValue(InneractiveAgeProperty); }
            set { SetValue(InneractiveAgeProperty, value); }
        }

        public static readonly DependencyProperty InneractiveAgeProperty = DependencyProperty.Register("InneractiveAge", typeof(string), typeof(AdRotatorControl), new PropertyMetadata(String.Empty, InneractiveAgeChanged));

        private static void InneractiveAgeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = d as AdRotatorControl;
            if (sender != null)
            {
                sender.OnInneractiveAgeChanged(e);
            }
        }

        private void OnInneractiveAgeChanged(DependencyPropertyChangedEventArgs e)
        {
            Invalidate();
        }


        #endregion

        #region InneractiveKeywords

        public string InneractiveKeywords
        {
            get { return (string)GetValue(InneractiveKeywordsProperty); }
            set { SetValue(InneractiveKeywordsProperty, value); }
        }

        public static readonly DependencyProperty InneractiveKeywordsProperty = DependencyProperty.Register("InneractiveKeywords", typeof(string), typeof(AdRotatorControl), new PropertyMetadata(String.Empty, InneractiveKeywordsChanged));

        private static void InneractiveKeywordsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = d as AdRotatorControl;
            if (sender != null)
            {
                sender.OnInneractiveKeywordsChanged(e);
            }
        }

        private void OnInneractiveKeywordsChanged(DependencyPropertyChangedEventArgs e)
        {
            Invalidate();
        }


        #endregion

        #region InneractiveReloadTime

        public int InneractiveReloadTime
        {
            get { return (int)GetValue(InneractiveReloadTimeProperty); }
            set { SetValue(InneractiveReloadTimeProperty, value); }
        }

        public static readonly DependencyProperty InneractiveReloadTimeProperty = DependencyProperty.Register("InneractiveReloadTime", typeof(int), typeof(AdRotatorControl), new PropertyMetadata(60, InneractiveReloadTimeChanged));

        private static void InneractiveReloadTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = d as AdRotatorControl;
            if (sender != null)
            {
                sender.OnInneractiveReloadTimeChanged(e);
            }
        }

        private void OnInneractiveReloadTimeChanged(DependencyPropertyChangedEventArgs e)
        {
            Invalidate();
        }


        #endregion      
        #endregion

        #region Smaato

        #region SmaatoPublisherId

        public string SmaatoPublisherId
        {
            get 
            {
                if (string.IsNullOrEmpty((string)GetValue(SmaatoPublisherIdProperty)))
                {
                    SetValue(SmaatoPublisherIdProperty,GetSecondaryID(AdType.Smaato));
                }
                return (string)GetValue(SmaatoPublisherIdProperty);
            }
            set { SetValue(SmaatoPublisherIdProperty, value); }
        }

        public static readonly DependencyProperty SmaatoPublisherIdProperty = DependencyProperty.Register("SmaatoPublisherId", typeof(string), typeof(AdRotatorControl), new PropertyMetadata("", SmaatoPublisherIdChanged));

        private static void SmaatoPublisherIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = d as AdRotatorControl;
            if (sender != null)
            {
                sender.OnSmaatoPublisherIdChanged(e);
            }
        }

        private void OnSmaatoPublisherIdChanged(DependencyPropertyChangedEventArgs e)
        {
            RemoveAdFromFailedAds(AdType.Smaato);
            Invalidate();
        }

        #endregion

        #region SmaatoAppId
        public string SmaatoAppId
        {
            get 
            {
                if (string.IsNullOrEmpty((string)GetValue(SmaatoAppIdProperty)))
                {
                    SetValue(SmaatoAppIdProperty,GetAppID(AdType.Smaato));
                }
                return (string)GetValue(SmaatoAppIdProperty);
            }
            set { SetValue(SmaatoAppIdProperty, value); }
        }

        public static readonly DependencyProperty SmaatoAppIdProperty = DependencyProperty.Register("SmaatoAppId", typeof(string), typeof(AdRotatorControl), new PropertyMetadata("", SmaatoAppIdChanged));

        private static void SmaatoAppIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = d as AdRotatorControl;
            if (sender != null)
            {
                sender.OnSmaatoAppIdChanged(e);
            }
        }

        private void OnSmaatoAppIdChanged(DependencyPropertyChangedEventArgs e)
        {
            RemoveAdFromFailedAds(AdType.Smaato);
            Invalidate();
        }
        #endregion

        #endregion

        #region DefaultSettingsFileUri

        public Uri DefaultSettingsFileUri
        {
            get { return (Uri)GetValue(DefaultSettingsFileUriProperty); }
            set { SetValue(DefaultSettingsFileUriProperty, value); }
        }

        public static readonly DependencyProperty DefaultSettingsFileUriProperty = DependencyProperty.Register("DefaultSettingsFileUri", typeof(Uri), typeof(AdRotatorControl), new PropertyMetadata(DefaultSettingsFileUriChanged));

        private static void DefaultSettingsFileUriChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = d as AdRotatorControl;
            if (sender != null)
            {
                sender.OnDefaultSettingsFileUriChanged(e);
            }
        }

        private void OnDefaultSettingsFileUriChanged(DependencyPropertyChangedEventArgs e)
        {
            FetchAdSettingsFile();
            if (_settings == null)
            {
                _settings = LoadAdSettings();
                Invalidate();
            }
        }

        #endregion

        #region AdValidSettings
        private bool IsPubCenterValid
        {
            get
            {
                return !String.IsNullOrEmpty(PubCenterAppId) && !String.IsNullOrEmpty(PubCenterAdUnitId);
            }
        }

        private bool IsAdDuplexValid
        {
            get
            {
                return !String.IsNullOrEmpty(AdDuplexAppId);
            }
        }

        private bool IsMobFoxValid
        {
            get
            {
                return !String.IsNullOrEmpty(MobFoxAppId);
            }
        }

        private bool IsAdMobValid
        {
            get
            {
                return !String.IsNullOrEmpty(AdMobAdUnitId);
            }
        }

        private bool IsSmaatoValid
        {
            get
            {
                int SmaatoIDTest;
                return (!String.IsNullOrEmpty(SmaatoAppId) && int.TryParse(SmaatoAppId, out SmaatoIDTest) && !String.IsNullOrEmpty(SmaatoPublisherId) && int.TryParse(SmaatoPublisherId, out SmaatoIDTest));
            }
        }
        #endregion

        public AdRotatorControl()
        {
            InitializeComponent();
            FetchAdSettingsFile();
            this.Loaded += new RoutedEventHandler(AdRotatorControl_Loaded);
        }

        void AdRotatorControl_Loaded(object sender, RoutedEventArgs e)
        {
            if (!NetworkInterface.GetIsNetworkAvailable() || NetworkInterface.NetworkInterfaceType == NetworkInterfaceType.None)
            {
                _isNetworkAvailable = false;
            }

            _loaded = true;
            Invalidate();


        }

        /// <summary>
        /// Fetches the ad settings file from the address specified at <see cref=""/>
        /// </summary>
        public void FetchAdSettingsFile()
        {
           if (_remoteAdSettingsFetched || !IsEnabled || String.IsNullOrEmpty(SettingsUrl))
            {
                return;
            }
           if (!_isNetworkAvailable)
           {
               _settings = GetDefaultSettings();
           }
           else
           {
               var request = (HttpWebRequest)WebRequest.Create(new Uri(SettingsUrl));
               request.BeginGetResponse(r =>
               {
                   try
                   {
                       var httpRequest = (HttpWebRequest)r.AsyncState;
                       var httpResponse = (HttpWebResponse)httpRequest.EndGetResponse(r);
                       var settingsStream = httpResponse.GetResponseStream();

                       var s = new XmlSerializer(typeof(AdSettings));
                       _settings = (AdSettings)s.Deserialize(settingsStream);
                       // Only persist the settings if they've been retreived from the remote file
                       SaveAdSettings(_settings);
                   }
                   catch
                   {
                       Dispatcher.BeginInvoke(() =>
                       {
                           _settings = GetDefaultSettings();
                       });
                   }
                   finally
                   {
                       _remoteAdSettingsFetched = true;
                       Dispatcher.BeginInvoke(Init);
                   }
               }, request);
           }
        }

        /// <summary>
        /// Displays a new ad
        /// </summary>
        /// <param name="selectNextAdType">If set to true, selects the next ad type in order, otherwise chooses 
        ///     a random one that hasn't had issues loading previously</param>
        /// <returns></returns>
        public string Invalidate(bool selectNextAdType = false)
        {
            string adTypeName = "";

            if (!_loaded)
            {
                OnLog("Control tested before loaded");
                return "";
            }
            if (!IsEnabled)
            {
                OnLog("No Ads available, control disabled");
                Visibility = Visibility.Collapsed;
                return adTypeName;
            }
            else
            {
                OnLog("Ads being served");
                Visibility = Visibility.Visible;
            }
            if (LayoutRoot == null)
            {
                OnLog("No layout to attach to");
                return adTypeName;
            }

            if (SlidingAdDirection != SlideDirection.None && !_slidingAdTimerStarted)
            {
                _slidingAdTimerStarted = true;
                ResetSlidingAdTimer(SlidingAdDisplaySeconds);           
            }

            RemoveEventHandlersFromAdControl();
            
            LayoutRoot.Children.Clear();
            AdType adType;
            if (selectNextAdType)
            {
                adType = CurrentAdType++;
                if (adType >= AdType.None)
                {
                    adType = AdType.None;
                }
            }
            else
            {
                adType = GetNextAdType();
            }
            OnLog(string.Format("Ads being requested for: {0}", adType.ToString()));
            switch (adType)
            {                
                case AdType.PubCenter:
                    _currentAdControl = CreatePubCentertAdControl();
                    break;
                case AdType.AdMob:
                    _currentAdControl = CreateAdMobAdControl();
                    break;
                case AdType.AdDuplex:
                    _currentAdControl = CreateAdDuplexControl();
                    break;
                case AdType.MobFox:
                    _currentAdControl = CreateMobFoxControl();
                    break;
                case AdType.InnerActive:
                    Visibility = Visibility.Visible;
                    bool success = CreateInneractiveControl(LayoutRoot);
                    if (!success)
                    {
                        OnAdLoadFailed(adType);
                    }
                    adTypeName = adType.ToString();
                    return adTypeName;
                case AdType.Smaato:
                    _currentAdControl = CreateSmaatoControl();
                    break;
                default:
                    return adTypeName;
                    //_currentAdControl = CreatePubCentertAdControl();
                    //break;                    
            }
            if (_currentAdControl == null)
            {
                OnAdLoadFailed(adType);
                OnLog(string.Format("Ads failed for: {0}", adType.ToString()));
                adTypeName = "failed - " + adType.ToString();
                return adTypeName;
            }
            if (adType == AdType.None)
            {
                OnLog("No ads available");
                Visibility = Visibility.Collapsed;
            }
            else
            {
                Visibility = Visibility.Visible;
                AddEventHandlersToAdControl();
                LayoutRoot.Children.Add(_currentAdControl);
            }

            adTypeName = adType.ToString();
            OnLog(string.Format("Ads being served for: {0}", adType.ToString()));
            return adTypeName;
        }

        /// <summary>
        /// Generates what the next ad type to display should be
        /// </summary>
        /// <returns></returns>
        private AdType GetNextAdType()
        {
            if (_currentCulture == null)
            {
                _currentCulture = GetAdDescriptorBasedOnUICulture();
            }

            if (_currentCulture == null)
            {
                return DefaultAdType;
            }

            var validDescriptors = _currentCulture.AdProbabilities
                .Where(x => !_failedAdTypes.Contains(x.AdType)
                            && IsAdTypeValid(x.AdType))
                .ToList();
            if (validDescriptors.Count == 0)
            {
                return DefaultAdType;
            }
            var totalValueBetweenValidAds = validDescriptors.Sum(x => x.ProbabilityValue);
            var randomValue = _rnd.NextDouble() * totalValueBetweenValidAds;
            double totalCounter = 0;
            foreach (var probabilityDescriptor in validDescriptors)
            {
                totalCounter += probabilityDescriptor.ProbabilityValue;
                if (randomValue < totalCounter)
                {
                    return probabilityDescriptor.AdType;
                }
            }
            return DefaultAdType;
        }

        /// <summary>
        /// Called when the settings have been loaded. Clears all failed ad types and invalidates the control
        /// </summary>
        private void Init()
        {
            _failedAdTypes.Clear();
            Invalidate();
        }

        private bool IsAdTypeValid(AdType adType)
        {
            switch (adType)
            {
                case AdType.PubCenter:
                    OnLog(string.Format("Testing \"{0}\" - Result {1}", adType.ToString(), IsPubCenterValid.ToString()));
                    return IsPubCenterValid;
                case AdType.AdDuplex:
                    OnLog(string.Format("Testing \"{0}\" - Result {1}", adType.ToString(), IsAdDuplexValid.ToString()));
                    return IsAdDuplexValid;
                case AdType.AdMob:
                    OnLog(string.Format("Testing \"{0}\" - Result {1}", adType.ToString(), IsAdMobValid.ToString()));
                    return IsAdMobValid;
                case AdType.MobFox:
                    OnLog(string.Format("Testing \"{0}\" - Result {1}", adType.ToString(), IsMobFoxValid.ToString()));
                    return IsMobFoxValid;
                case AdType.Smaato:
                    OnLog(string.Format("Testing \"{0}\" - Result {1}", adType.ToString(), IsSmaatoValid.ToString()));
                    return IsSmaatoValid;
                   
            }
            //Davide Cleopadre www.cleosolutions.com
            //if for any reason the AdType cannot be found is not valid
            //if we add new ads type the control will continue to work
            //also not updated
            return false; 
        }

        private void AddEventHandlersToAdControl()
        {
            var pubCenterAd = _currentAdControl as Microsoft.Advertising.Mobile.UI.AdControl;
            if (pubCenterAd != null)
            {
                pubCenterAd.AdRefreshed += new EventHandler(pubCenterAd_AdRefreshed);
                pubCenterAd.ErrorOccurred += new EventHandler<Microsoft.Advertising.AdErrorEventArgs>(pubCenterAd_ErrorOccurred);
            }
            var adMobAd = _currentAdControl as Google.AdMob.Ads.WindowsPhone7.WPF.BannerAd;
            if (adMobAd != null)
            {
                adMobAd.AdFailed += adMobAd_AdFailed;
                adMobAd.AdReceived += adMobAd_AdReceived;
                adMobAd.AdLeavingApplication += adMobAd_AdLeavingApplication;
                adMobAd.AdPresentingScreen += adMobAd_AdPresentingScreen;
            }
            var somaAd = _currentAdControl as SOMAWP7.SomaAdViewer;
            if (somaAd != null)
            {
                somaAd.NewAdAvailable += somaAd_NewAdAvailable;
                somaAd.AdError += somaAd_AdError;
            }
            var mobFoxAd = _currentAdControl as MobFox.Ads.AdControl;
            if (mobFoxAd != null)
            {
                mobFoxAd.NoAd += new MobFox.Ads.NoAdEventHandler(mobFox_NoAd);
                mobFoxAd.NewAd += new MobFox.Ads.NewAdEventHandler(mobFox_NewAd);
            }
        }

        private void RemoveEventHandlersFromAdControl()
        {
            var pubCenterAd = _currentAdControl as Microsoft.Advertising.Mobile.UI.AdControl;
            if (pubCenterAd != null)
            {
                pubCenterAd.AdRefreshed -= new EventHandler(pubCenterAd_AdRefreshed);
                pubCenterAd.ErrorOccurred -= new EventHandler<Microsoft.Advertising.AdErrorEventArgs>(pubCenterAd_ErrorOccurred);
            }
            var adMobAd = _currentAdControl as Google.AdMob.Ads.WindowsPhone7.WPF.BannerAd;
            if (adMobAd != null)
            {
                adMobAd.AdFailed -= new Google.AdMob.Ads.WindowsPhone7.ErrorEventHandler(adMobAd_AdFailed);
                adMobAd.AdReceived -= new RoutedEventHandler(adMobAd_AdReceived);
            }
            var somaAd = _currentAdControl as SOMAWP7.SomaAdViewer;
            if (somaAd != null)
            {
                somaAd.NewAdAvailable -= somaAd_NewAdAvailable;
                somaAd.AdError -= somaAd_AdError;
            }
            var mobFoxAd = _currentAdControl as MobFox.Ads.AdControl; 
            if (mobFoxAd != null) 
            { 
                mobFoxAd.NoAd -= new MobFox.Ads.NoAdEventHandler(mobFox_NoAd); 
                mobFoxAd.NewAd -= new MobFox.Ads.NewAdEventHandler(mobFox_NewAd); 
            }
        }

        private AdCulture GetAdDescriptorBasedOnUICulture()
        {
            if (_settings == null || _settings.CultureDescriptors == null)
            {
                return null;
            }
            var cultureLongName = Thread.CurrentThread.CurrentUICulture.Name;
            if(String.IsNullOrEmpty(cultureLongName))
            {
                cultureLongName = AdSettings.DEFAULT_CULTURE;
            }
            var cultureShortName = cultureLongName.Substring(0, 2);
            var descriptor = _settings.CultureDescriptors.Where(x => x.CultureName == cultureLongName).FirstOrDefault();
            if (descriptor != null)
            {
                return descriptor;
            }
            var sameLanguageDescriptor = _settings.CultureDescriptors.Where(x => x.CultureName.StartsWith(cultureShortName)).FirstOrDefault();
            if (sameLanguageDescriptor != null)
            {
                return sameLanguageDescriptor;
            }
            var defaultDescriptor = _settings.CultureDescriptors.Where(x => x.CultureName == AdSettings.DEFAULT_CULTURE).FirstOrDefault();
            if (defaultDescriptor != null)
            {
                return defaultDescriptor;
            }
            return null;
        }

        private void RemoveAdFromFailedAds(AdType adType)
        {
            if(_failedAdTypes.Contains(adType))
            {
                _failedAdTypes.Remove(adType);
            }
        }

        /// <summary>
        /// Called when <paramref name="adType"/> has failed to load
        /// </summary>
        /// <param name="adType"></param>
        private void OnAdLoadFailed(AdType adType)
        {
            OnLog(string.Format("Ads failed request for: {0}", adType.ToString()));
            if (!_failedAdTypes.Contains(adType))
            {
                _failedAdTypes.Add(adType);
            }
            Dispatcher.BeginInvoke(() =>
            {
                Invalidate();
            });
        }

        /// <summary>
        /// Called when <paramref name="adType"/> has succeeded to load
        /// </summary>
        /// <param name="adType"></param>
        private void OnAdLoadSucceeded(AdType adType)
        {
            OnLog(string.Format("Ads being successfully served for: {0}", adType.ToString()));
            if (_failedAdTypes.Contains(adType))
            {
                _failedAdTypes.Remove(adType);
            }
        }

        private string GetAppID(AdType adType)
        {
            return _currentCulture.AdProbabilities
                    .Where(x => x.AdType == adType)
                    .First().AppID;
        }

        private string GetSecondaryID(AdType adType)
        {
            return _currentCulture.AdProbabilities
                    .Where(x => x.AdType == adType)
                    .First().SecondaryID;
        }

        private void SaveAdSettings()
        {
        }

        /// <summary>
        /// Loads the ad settings object either from isolated storage or from the resource path defined in DefaultSettingsFileUri.
        /// </summary>
        /// <returns></returns>
        private AdSettings LoadAdSettings()
        {
            try
            {
                var isfData = IsolatedStorageFile.GetUserStoreForApplication();
                IsolatedStorageFileStream isfStream = null;
                if (isfData.FileExists(SETTINGS_FILE_NAME))
                {
                    using (isfStream = new IsolatedStorageFileStream(SETTINGS_FILE_NAME, FileMode.Open, isfData))
                    {
                        XmlSerializer xs = new XmlSerializer(typeof(AdSettings));
                        try
                        {
                            var settings = (AdSettings)xs.Deserialize(isfStream);
                            return settings;
                        }
                        catch
                        {

                        }
                    }
                }
            }
            catch (IsolatedStorageException)
            {
            }

            if (_settings == null)
            {
                _settings = GetDefaultSettings();
            }
            return _settings;
        }

        private AdSettings GetDefaultSettings()
        {
            if (DefaultSettingsFileUri != null)
            {
                var defaultSettingsFileInfo = Application.GetResourceStream(DefaultSettingsFileUri);
                var xs = new XmlSerializer(typeof(AdSettings));
                try
                {
                    var settings = (AdSettings)xs.Deserialize(defaultSettingsFileInfo.Stream);
                    return settings;
                }
                catch (Exception e)
                {
                    var error = e;
                }
            }
            return new AdSettings();
        }

        /// <summary>
        /// Saves the passed settings file to isolated storage
        /// </summary>
        /// <param name="settings"></param>
        private static void SaveAdSettings(AdSettings settings)
        {
            try
            {
                XmlSerializer xs = new XmlSerializer(typeof(AdSettings));
                IsolatedStorageFileStream isfStream = new IsolatedStorageFileStream(SETTINGS_FILE_NAME, FileMode.Create, IsolatedStorageFile.GetUserStoreForApplication());
                xs.Serialize(isfStream, settings);
                isfStream.Close();
            }
            catch
            {
            }
        }

        #region Specific ad controls


        private bool CreateInneractiveControl(Grid container)
        {
            try
            {
                Dictionary<InneractiveAd.IaOptionalParams, string> optionalParams = new Dictionary<InneractiveAd.IaOptionalParams, string>();
                optionalParams.Add(InneractiveAd.IaOptionalParams.Key_Distribution_Id, "659");
                if (InneractiveExternalId != String.Empty)
                {
                    optionalParams.Add(InneractiveAd.IaOptionalParams.Key_External_Id, InneractiveExternalId);
                }
                if (InneractiveGender != String.Empty)
                {
                    optionalParams.Add(InneractiveAd.IaOptionalParams.Key_Gender, InneractiveGender);
                }
                if (InneractiveAge != String.Empty)
                {
                    optionalParams.Add(InneractiveAd.IaOptionalParams.Key_Age, InneractiveAge);
                }
                if (InneractiveKeywords != String.Empty)
                {
                    optionalParams.Add(InneractiveAd.IaOptionalParams.Key_Keywords, InneractiveKeywords);
                }

                return InneractiveAd.DisplayAd(InneractiveAppId, InneractiveAd.IaAdType.IaAdType_Banner, container, InneractiveReloadTime, optionalParams);
            }
            catch (Exception)
            {
                return false;
            }         
        }

        private FrameworkElement CreateMobFoxControl()
        {
            try
            {
                var MobFoxAd = new MobFox.Ads.AdControl();
                MobFoxAd.PublisherID = MobFoxAppId;
                MobFoxAd.AutoRotate = true;
                MobFoxAd.TestMode = MobFoxIsTest;
                MobFoxAd.RequestNextAd();
                return MobFoxAd;
            }
            catch (Exception)
            {
                return null;
            }
        }

        private FrameworkElement CreateAdMobAdControl()
        {
            try
            {
                var adMobAd = new Google.AdMob.Ads.WindowsPhone7.WPF.BannerAd();
                adMobAd.AdUnitID = AdMobAdUnitId;
                return adMobAd;
            }
            catch (Exception)
            {
               return null;
            }
        }

        private FrameworkElement CreateSmaatoControl()
        {
            try
            {
                var SomaAd = new SOMAWP7.SomaAdViewer();
                SomaAd.Pub = int.Parse(SmaatoPublisherId);
                SomaAd.Adspace = int.Parse(SmaatoAppId);
                SomaAd.AdSpaceWidth = 480;
                SomaAd.AdSpaceHeight = 100;
                SomaAd.LocationUseOK = true;
                SomaAd.PopupAd = false;
                //Note - Do NOT use the Debug flag as it has issues
                SomaAd.StartAds();
                return SomaAd;
            }
            catch (Exception)
            {
                return null;
            }
        }

        void adMobAd_AdReceived(object sender, RoutedEventArgs e)
        {
            OnLog(string.Format("Admob Success:"));
            OnAdLoadSucceeded(AdType.AdMob);
        }

        void adMobAd_AdFailed(object sender, Google.AdMob.Ads.WindowsPhone7.AdException exception)
        {
            OnLog(string.Format("Admob Failed: {0}", exception.Message.ToString()));
            OnAdLoadFailed(AdType.AdMob);
        }

        private void adMobAd_AdLeavingApplication(object sender, RoutedEventArgs e)
        {
        }

        private void adMobAd_AdPresentingScreen(object sender, RoutedEventArgs e)
        {
        }

         void pubCenterAd_AdRefreshed(object sender, EventArgs e)
        {
            OnLog(string.Format("pubCenter Success: {0}", e.ToString()));
            OnAdLoadSucceeded(AdType.PubCenter);
        }

        void pubCenterAd_ErrorOccurred(object sender, Microsoft.Advertising.AdErrorEventArgs e)
        {
            OnLog(string.Format("PubCenter Failed: {0}", e.Error.Message.ToString()));
            OnAdLoadFailed(AdType.PubCenter);
        }

        void somaAd_AdError(object sender, string ErrorCode, string ErrorDescription)
        {
            OnLog(string.Format("Smaato Failed: {0} - {1} ", ErrorCode, ErrorDescription));
            OnAdLoadFailed(AdType.Smaato);
        }

        void somaAd_NewAdAvailable(object sender, EventArgs e)
        {
            OnLog(string.Format("Smaato Success: {0}", e.ToString()));
            OnAdLoadSucceeded(AdType.Smaato);
        }

        void mobFox_NewAd(object sender, MobFox.Ads.NewAdEventArgs e) 
        { 
            OnAdLoadSucceeded(AdType.MobFox); 
        }

        void mobFox_NoAd(object sender, MobFox.Ads.NoAdEventArgs e) 
        { 
            OnAdLoadFailed(AdType.MobFox); 
        }

        #endregion

        #region Animation Events
        private void SlideOutAdStoryboard_Completed(object sender, EventArgs e)
        {
            _slidingAdHidden = true;
            Invalidate();
            ResetSlidingAdTimer(SlidingAdHiddenSeconds);
        }

        private void SlideInAdStoryboard_Completed(object sender, EventArgs e)
        {
            _slidingAdHidden = false;
            ResetSlidingAdTimer(SlidingAdDisplaySeconds);
        }

        private void ResetSlidingAdTimer(int durationInSeconds)
        {
            SlidingAdTimer.Duration = new TimeSpan(0, 0, durationInSeconds);
            SlidingAdTimer.Begin();
        }

        private void SlidingAdTimer_Completed(object sender, EventArgs e)
        {
            switch (SlidingAdDirection)
            {
                case SlideDirection.Top:
                case SlideDirection.Bottom:
                    if (_slidingAdHidden)
                    {
                        SlideInUDAdStoryboard.Begin();
                    }
                    else
                    {
                        SlideOutUDAdStoryboard.Begin();
                    }
                    break;
                case SlideDirection.Left:
                case SlideDirection.Right:
                    if (_slidingAdHidden)
                    {
                        SlideInLRAdStoryboard.Begin();
                    }
                    else
                    {
                        SlideOutLRAdStoryboard.Begin();
                    }
                    break;
                default:
                    break;
            }
        }
        #endregion

        public void Dispose()
        {
            LayoutRoot.Children.Clear();
            _currentAdControl = null;
        }
    }
}
